package org.hit.burkun.network.tester;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;

import org.hit.burkun.entities.Entity;
import org.hit.burkun.file.FileHelper;
import org.hit.burkun.network.EdgeInfo;
import org.hit.burkun.network.GraphFeatures;
import org.hit.burkun.network.SerializableGraph;
import org.hit.burkun.network.Vertex;
import org.hit.burkun.network.models.StaticMethods;
import org.hit.burkun.umls.relation.UniformRelation;

public class ValidData {

	public static void main(String[] args) {
		 File[] files = FileHelper.getDirFile("data/ranking", ".txt");
		 for(File f : files){
			 System.out.println(f.getName());
			 System.out.println(calcRecallRank(f.getAbsolutePath()));
		 }
//		 File[] files = FileHelper.getDirFile("data/linkpredict/halfvalid/srw", ".txt");
//		 for(File f : files){
//			 System.out.println(f.getName());
//			 System.out.println(calcAuc(f.getAbsolutePath()));
//		 }
//
//		 File[] files1 = FileHelper.getDirFile("data/rwr-change-alpha/train1", ".txt");
//		 for(File f : files1){
//			 System.out.println(f.getName());
//			 System.out.println(calcAuc(f.getAbsolutePath()));
//		 }
//		 
//		 File[] files3 = FileHelper.getDirFile("data/rwr-change-alpha/nodir-train1", ".txt");
//		 for(File f : files3){
//			 System.out.println(f.getName());
//			 System.out.println(calcAuc(f.getAbsolutePath()));
//		 }
		 
		 File[] files2 = FileHelper.getDirFile("data/linkpredict/halfvalid/sln", ".txt");
		 for(File f : files2){
			 System.out.println(f.getName());
			 System.out.println(calcAuc(f.getAbsolutePath()));
		 }
//		SerializableGraph sg = StaticMethods.loadGraphNoDir();
//		saveTestObj(sg);
//		writeValidDataToFile(sg);
//		splitTestToTrainAndValid();

//		 HashMap<String, HashSet<EdgeInfo>> testFalse= readTestFalseObj();
//		 HashMap<String, HashSet<EdgeInfo>> testTrue= readTestTrueObj();
//		 System.out.println(getTestCounter(testFalse));
//		 System.out.println(getTestCounter(testTrue));


		System.out.println(calcAuc("data/final/pr2-nodir-wight-1.0-a-0.65.txt"));
		System.out.println(calcAuc("data/final/v-weigth-salpha-0.4-sample-1.0-opt-0.4.txt"));
		System.out.println(calcAuc("data/final/v-weigth-salpha-0.2-sample-1.0-opt.txt"));
	
	}

	/*
	 * C0002395 DOID:10652,HP:0002511 C0002871 DOID:2355 C0002878
	 * DOID:583,HP:0001878,HP:0001930 C0007959 DOID:10595 C0013421
	 * HP:0001332,DOID:543 C0013720 DOID:13359 C0014544 DOID:1826 ......
	 * C0023418 DOID:1240 HP:0001909 C0024299 DOID:0060058 HP:0002665 C0025362
	 * DOID:1059 HP:0001249 C0026850 DOID:9884 HP:0003560 C0026848 DOID:423
	 * HP:0003198 C0442874 DOID:870(no gene) C0028754 DOID:9970(鑲ヨ儢) C0030567
	 * DOID:14330 C0035334 HP:0008035 C0037772 HP:0001258 C0087012 DOID:1441
	 * HP:0007263 C0043459 DOID:905
	 */

	private static HashSet<String> validUmls = new HashSet<>();
	private static HashSet<String> validFilter = new HashSet<>();
	private static String geneType = Entity.TYPE.GENE_ID.getTag();
	static {
		validUmls.add("C0002871");
		validUmls.add("C0002878");
		validUmls.add("C0878544"); // to big
		validUmls.add("C0007959");
		// evidence
		validUmls.add("C0011849"); // 鏇夸唬C0011847 绯栧翱鐥�
		validUmls.add("C0013421");
		validUmls.add("C0023418");
		validUmls.add("C0024299");
		validUmls.add("C0026850");
		validUmls.add("C0026848");
		validUmls.add("C0030567"); //too big
		validUmls.add("C0035334"); //to big
		validUmls.add("C0037773"); // 鏇夸唬 C0037772
		validUmls.add("NMAP12546");
		validUmls.add("NMAP12777");
		validUmls.add("C0043459");
		//-add new 
		//validUmls.add("C0002736");
		//validUmls.add("C0028754");
		

		validFilter.add(UniformRelation.TYPE.DO_SIDD_MFR_OMIM_GENE.getTag());
		validFilter.add(UniformRelation.TYPE.DO_SIDD_MFR_MESH_GENE.getTag());
		validFilter.add(UniformRelation.TYPE.DO_SIDD_MFS_MESH_GENE.getTag());
		validFilter.add(UniformRelation.TYPE.DO_SIDD_MFS_OMIM_GENE.getTag());
		// validFilter.add(UniformRelation.TYPE.HP_ANNOTATION_GENE_PCS.getTag());
		// validFilter.add(UniformRelation.TYPE.HP_ANNOTATION_GENE_ICE.getTag());
		validFilter.add(UniformRelation.TYPE.DISEASE_CTD_GENE_CURATED.getTag());
		validFilter.add(UniformRelation.TYPE.DO_XREF_OMIM_GENE.getTag());
		validFilter.add(UniformRelation.TYPE.OMIM_GENE.getTag());
		validFilter.add(UniformRelation.TYPE.DISEASE_CLINVAR_GENE.getTag());

	}

	public static HashSet<String> getValidFilter() {
		return validFilter;
	}

	public static boolean isValidData(String umls, String vumls) {
		if (umls.equals(vumls))
			return true;
		String[] uml = umls.split(",");
		for (String u : uml) {
			if (vumls.equals(u)) {
				return true;
			}
		}
		return false;
	}

	public static HashSet<String> getValidUmls() {
		return validUmls;
	}

	public static HashSet<EdgeInfo> splitVaildData(SerializableGraph sg,
			String umls) {
		Collection<Vertex> vv = sg.getAllVertexs();
		for (Vertex v : vv) {
			if (isValidData(v.getUmlsId(), umls)) {
				// valid data
				HashSet<EdgeInfo> vs = new HashSet<>();
				LinkedList<EdgeInfo> edges = sg.getNeighborsByVertex(v);
				for (EdgeInfo e : edges) {
					if (e.getVertex().isInNodeTypes(geneType)
							&& e.isInRelType(validFilter)) {
						if (sg.getNeighborsByVertex(e.getVertex()).size() > 1) {
							vs.add(e);
						}
					}
				}
				return vs;
			}
		}
		return null;
	}

	public static void writeValidDataToFile(SerializableGraph sg) {
		LinkedList<String> res = new LinkedList<>();
		HashSet<Integer> set = new HashSet<>();
		for (String umls : validUmls) {
			HashSet<EdgeInfo> sets = splitVaildData(sg, umls);
			StringBuilder sb = new StringBuilder();
			sb.append(umls + ": ");
			if (sets != null) {
				for (EdgeInfo e : sets) {
					sb.append(e.getVertex().getDbids() + ",");
					set.add(e.getVertex().getUid());
				}
				sb.append(sets.size());
			}
			res.add(sb.toString());
		}
		FileHelper.writeFile("data/valid.txt", res);
	}

	// ---auc
	public static double calcAuc(String fileName) {
		Collection<String> res = FileHelper.readFile(fileName);
		ArrayList<UmlsWithSocre> scores = new ArrayList<UmlsWithSocre>();
		HashMap<String, Integer> mapFlag = new HashMap<>();
		double maxS = 0;
		double minS = 1;
		for (String line : res) {
			String[] items = line.split("\\$");
			String[] scoreTag = items[1].split("-");
			double score = 0;
			if (scoreTag.length > 2) {
				score = Double.parseDouble(scoreTag[0] + "-" + scoreTag[1]);
			} else {
				score = Double.parseDouble(scoreTag[0]);
			}
			if (score > maxS)
				maxS = score;
			if (score < minS)
				minS = score;
			String tag = scoreTag[scoreTag.length - 1];
			String key = items[0].split("\\|")[0];
			scores.add(new UmlsWithSocre(key, score));
			mapFlag.put(key, Integer.parseInt(tag));
		}
		/*
		 * http://www.tuicool.com/articles/qYNNF3
		 */
		ArrayList<String> matlabRes = new ArrayList<>();
		Collections.sort(scores);
		int counter = 0;
		int sumsPreTrue = 0;
		int sumsFalse = 0;
		int sumsTrue = 0;
		for (UmlsWithSocre us : scores) {
			counter += 1;
			if (mapFlag.get(us.umls) == 1) {
				sumsPreTrue += counter;
				sumsTrue += 1;
				matlabRes.add(1+"," + us.score);
			} else {
				sumsFalse += 1;
				matlabRes.add(0+"," + us.score);
			}
		}
		FileHelper.writeFile(fileName+".mat.csv", matlabRes);
		return (sumsPreTrue - sumsTrue * (sumsTrue + 1) / 2)
				/ (sumsFalse * sumsTrue + 0.0);
	}

	// ---计算AUC和std
	public static double calcRecallRank(String fileName) {
		Collection<String> res = FileHelper.readFile(fileName);
		ArrayList<Double> arr = new ArrayList<Double>();
		for (String line : res) {
			String[] items = line.split(":");
			String val = items[items.length - 1];
			double top = Double.parseDouble(val);
			arr.add(top);
		}
		// 计算AUC
		double sums = 0;
		for (int i = 0; i <= 10000; i++) {
			int counter = 0;
			for (double value : arr) {
				if (value <= i / 10000.0) {
					counter += 1;
				}
			}
			sums += counter;
		}
		double a = sums / 10000 / arr.size();
		return a;
	}
	


	// -----------------------TEST DATA-----------------------------

	public static int getTestCounter(HashMap<String, HashSet<EdgeInfo>> test) {
		int counter = 0;
		Set<Entry<String, HashSet<EdgeInfo>>> entries = test.entrySet();
		for (Entry<String, HashSet<EdgeInfo>> entry : entries) {
			counter += entry.getValue().size();
		}
		return counter;
	}

	public static SerializableGraph getRemovedSg(boolean useDir,
			HashMap<String, HashSet<EdgeInfo>> maps) {
		SerializableGraph sg = null;
		if (useDir) {
			sg = StaticMethods.loadGraphDir();
		} else {
			sg = StaticMethods.loadGraphNoDir();
		}
		// System.out.println(StaticMethods.counterVertexAndEdges(sg));
		Set<Entry<String, HashSet<EdgeInfo>>> entries = maps.entrySet();
		for (Entry<String, HashSet<EdgeInfo>> entry : entries) {
			String uml = entry.getKey();
			HashSet<EdgeInfo> edges = entry.getValue();
			for (EdgeInfo e : edges) {
				GraphFeatures.removeEdgeFromNetWork(sg, uml, e);
			}
		}
		// System.out.println(StaticMethods.counterVertexAndEdges(sg));
		return sg;
	}

	public static HashMap<String, HashSet<EdgeInfo>> getTestSet(
			SerializableGraph sg) {
		HashSet<String> umls = getValidUmls();
		HashMap<String, HashSet<EdgeInfo>> maps = new HashMap<>();
		for (String u : umls) {
			HashSet<EdgeInfo> edges = splitVaildData(sg, u);
			for (EdgeInfo e : edges) {
				//以几分之几选择
				if (!isChoose(1)) {
					if (!maps.containsKey(u)) {
						HashSet<EdgeInfo> sets = new HashSet<>();
						sets.add(e);
						maps.put(u, sets);
					} else {
						maps.get(u).add(e);
					}
				}
			}
		}

		return maps;
	}

	public static HashMap<String, HashSet<EdgeInfo>> getRandomNagtativeSample(
			HashMap<String, HashSet<EdgeInfo>> maps, SerializableGraph sg) {
		Collection<HashSet<EdgeInfo>> allEdges = maps.values();
		HashMap<String, HashSet<EdgeInfo>> randomEdges = new HashMap<>();
		ArrayList<EdgeInfo> all = new ArrayList<>();
		for (HashSet<EdgeInfo> es : allEdges) {
			all.addAll(es);
		}
		Collection<String> keys = maps.keySet();
		for (String u : keys) {
			// add the same size of nagtive edges
			int edgesize = maps.get(u).size();
			HashSet<EdgeInfo> curEdges = maps.get(u);
			int curSize = 0;
			while (true) {
				if (curSize == edgesize) {
					break;
				} else {
					int idx = rand.nextInt(all.size());
					if (!curEdges.contains(all.get(idx))) {
						LinkedList<EdgeInfo> tempEdges = sg
								.getNeighborsByVertex(sg.getVertexByUmls(u));
						boolean isIn = false;
						for (EdgeInfo e : tempEdges) {
							if (e.getVertex().getUid() == all.get(idx)
									.getVertex().getUid()) {
								isIn = true;
								break;
							}
						}
						if (!isIn) {
							if (randomEdges.containsKey(u)) {
								randomEdges.get(u).add(all.get(idx));
							} else {
								HashSet<EdgeInfo> sets = new HashSet<>();
								sets.add(all.get(idx));
								randomEdges.put(u, sets);
							}
							curSize += 1;
						}
					}
				}
			}
		}
		return randomEdges;
	}

	@SuppressWarnings("unchecked")
	public static HashMap<String, HashSet<EdgeInfo>> readTestTrueObj() {
		return (HashMap<String, HashSet<EdgeInfo>>) SerializableGraph
				.readObject(new File("data/testTrue.obj"));
	}

	@SuppressWarnings("unchecked")
	public static HashMap<String, HashSet<EdgeInfo>> readTestFalseObj() {
		return (HashMap<String, HashSet<EdgeInfo>>) SerializableGraph
				.readObject(new File("data/testFalse.obj"));
	}

	
	@SuppressWarnings("unchecked")
	public static HashMap<String, HashSet<EdgeInfo>> readTestFalseTrainObj() {
		return (HashMap<String, HashSet<EdgeInfo>>) SerializableGraph
				.readObject(new File("data/testFalseTrain.obj"));
	}

	@SuppressWarnings("unchecked")
	public static HashMap<String, HashSet<EdgeInfo>> readTestTrueTrainObj() {
		return (HashMap<String, HashSet<EdgeInfo>>) SerializableGraph
				.readObject(new File("data/testTrueTrain.obj"));
	}
	
	@SuppressWarnings("unchecked")
	public static HashMap<String, HashSet<EdgeInfo>> readTestTrueValidObj() {
		return (HashMap<String, HashSet<EdgeInfo>>) SerializableGraph
				.readObject(new File("data/testTrueValid.obj"));
	}

	@SuppressWarnings("unchecked")
	public static HashMap<String, HashSet<EdgeInfo>> readTestFalseValidObj() {
		return (HashMap<String, HashSet<EdgeInfo>>) SerializableGraph
				.readObject(new File("data/testFalseValid.obj"));
	}
	
	public static void saveTestObj(SerializableGraph sg) {
		try {
			HashMap<String, HashSet<EdgeInfo>> trueTest = getTestSet(sg);
			SerializableGraph.writeObject(new File("data/testTrue.obj"),
					trueTest);
			SerializableGraph.writeObject(new File("data/testFalse.obj"),
					getRandomNagtativeSample(trueTest, sg));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static Random rand = new Random();

	private static boolean isChoose(int i) {
		if(i == 1) return true;
		return rand.nextInt(i) > i-2 ;
		//return true;
	}
	
	
	public static void splitTestToTrainAndValid(){
		//生成训练和测试
		HashMap<String, HashSet<EdgeInfo>> testFalse = readTestFalseObj();
		HashMap<String, HashSet<EdgeInfo>> testTrue = readTestTrueObj();
		HashMap<String, HashSet<EdgeInfo>> testFalseTrain = new HashMap<String, HashSet<EdgeInfo>>();
		HashMap<String, HashSet<EdgeInfo>> testFalseValid = new HashMap<String, HashSet<EdgeInfo>>();
		HashMap<String, HashSet<EdgeInfo>> testTrueTrain = new HashMap<String, HashSet<EdgeInfo>>();
		HashMap<String, HashSet<EdgeInfo>> testTrueValid = new HashMap<String, HashSet<EdgeInfo>>();

		for(String key : testFalse.keySet()){
			HashSet<EdgeInfo> edges = testFalse.get(key);
			for(EdgeInfo e : edges){
				if(isChoose(2)){
					if(testFalseValid.containsKey(key)){
						testFalseValid.get(key).add(e);
					}else{
						HashSet<EdgeInfo> ed = new HashSet<>();
						ed.add(e);
						testFalseValid.put(key, ed);
					}
				}else{
					if(testFalseTrain.containsKey(key)){
						testFalseTrain.get(key).add(e);
					}else{
						HashSet<EdgeInfo> ed = new HashSet<>();
						ed.add(e);
						testFalseTrain.put(key, ed);
					}
				}
			}
		}
		for(String key : testTrue.keySet()){
			HashSet<EdgeInfo> edges = testTrue.get(key);
			for(EdgeInfo e : edges){
				if(isChoose(2)){
					if(testTrueValid.containsKey(key)){
						testTrueValid.get(key).add(e);
					}else{
						HashSet<EdgeInfo> ed = new HashSet<>();
						ed.add(e);
						testTrueValid.put(key, ed);
					}
				}else{
					if(testTrueTrain.containsKey(key)){
						testTrueTrain.get(key).add(e);
					}else{
						HashSet<EdgeInfo> ed = new HashSet<>();
						ed.add(e);
						testTrueTrain.put(key, ed);
					}
				}
			}
		}
		try {
			SerializableGraph.writeObject(new File("data/testTrueTrain.obj"),testTrueTrain);
			SerializableGraph.writeObject(new File("data/testFalseTrain.obj"),testFalseTrain);
			SerializableGraph.writeObject(new File("data/testTrueValid.obj"),
					testTrueValid);
			SerializableGraph.writeObject(new File("data/testFalseValid.obj"),
					testFalseValid);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	
	
}



class UmlsWithSocre implements Comparable<UmlsWithSocre> {
	public String umls;
	public double score;

	@Override
	public int compareTo(UmlsWithSocre o) {
		return Double.compare(score, o.score);
	}

	public UmlsWithSocre(String umls, double score) {
		super();
		this.umls = umls;
		this.score = score;
	}

}
